#include "kernel.cuh"
#include "denseMatrix.cuh"
#include "cuda_runtime.h"
#include "device_launch_parameters.h"


void denseMatrix_t::allocateData(int numRows, int numCols){
	this->data = new double[numRows * numCols];
	this->numRows = numRows;
	this->numCols = numCols;
}

void denseMatrix_t::allocateDataGPU(int numRows, int numCols){
	cudaError_t status = cudaSuccess;

	status = cudaMalloc(&data, numRows * numCols * sizeof(double));
	logStatus(status, "Memory Allocation");

	this->numCols = numCols;
	this->numRows = numRows;
}

denseMatrix_t* denseMatrix_t::copyMatrixToGPU(int numRows, int numCols){
	denseMatrix_t *onDevice;
	cudaError_t status = cudaSuccess;
	
	status = cudaMalloc(&onDevice, sizeof(denseMatrix_t));
	logStatus(status, "Memory allocation");

	status = cudaMemcpy(onDevice, this, sizeof(denseMatrix_t), cudaMemcpyHostToDevice);
	logStatus(status, "Memory Copy");

	return onDevice;
}

void denseMatrix_t::copyDataToGPU(denseMatrix_t onDevice){
	cudaError_t status = cudaSuccess;

	status = cudaMemcpy(onDevice.data, this->data, this->numCols * this->numRows * sizeof(double), cudaMemcpyHostToDevice);
	logStatus(status, "Memory copy to GPU");
}

denseMatrix_t* denseMatrix_t::transferMatrixToGPU(){
	denseMatrix_t *onHost = new denseMatrix_t;
	onHost->allocateDataGPU(numRows, numCols);
	onHost->onDevice = onHost->copyMatrixToGPU(numRows, numCols);
	copyDataToGPU(*(onHost));
	return onHost;
}

void denseMatrix_t::copyDataToCPU(denseMatrix_t onDevice){
	cudaError_t status = cudaSuccess;

	status = cudaMemcpy(this->data, onDevice.data, this->numCols * this->numRows * sizeof(double), cudaMemcpyDeviceToHost);
	logStatus(status, "Memory copy Device to Host");
}

int denseMatrix_t::nonNullElements(){
	int i,j;
	j=0;
	for(i=0;i<numRows*numCols;i++){
		if(data[i] != 0)j++;
	}
	return j;
}

void denseMatrix_t::deallocate(){
	delete[] data;
	return;
}

void denseMatrix_t::deallocateGPU(){
	cudaError_t status = cudaSuccess;
	status = cudaFree(data);
	logStatus(status, "Deallocate Memory");
	return;
}

int denseMatrix_t::index(int x, int y){
	return x*numCols + y;
}
